home *** CD-ROM | disk | FTP | other *** search
/ CD Actual Thematic 7: Programming / CDAT7.iso / Share / Codigo / hh / rsource.exe / Hexen Source / P_SPEC.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-22  |  28.8 KB  |  1,153 lines

  1.  
  2. //**************************************************************************
  3. //**
  4. //** p_spec.c : Heretic 2 : Raven Software, Corp.
  5. //**
  6. //** $RCSfile: p_spec.c,v $
  7. //** $Revision: 1.67 $
  8. //** $Date: 96/01/06 18:37:33 $
  9. //** $Author: bgokey $
  10. //**
  11. //**************************************************************************
  12.  
  13. // HEADER FILES ------------------------------------------------------------
  14.  
  15. #include "h2def.h"
  16. #include "p_local.h"
  17. #include "soundst.h"
  18.  
  19. // MACROS ------------------------------------------------------------------
  20.  
  21. #define MAX_TAGGED_LINES 64
  22.  
  23. // TYPES -------------------------------------------------------------------
  24.  
  25. // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
  26.  
  27. // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
  28.  
  29. // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
  30.  
  31. static boolean CheckedLockedDoor(mobj_t *mo, byte lock);
  32.  
  33. // EXTERNAL DATA DECLARATIONS ----------------------------------------------
  34.  
  35. // PUBLIC DATA DEFINITIONS -------------------------------------------------
  36.  
  37. int *TerrainTypes;
  38. struct
  39. {
  40.     char *name;
  41.     int type;
  42. } TerrainTypeDefs[] =
  43. {
  44.     { "X_005", FLOOR_WATER },
  45.     { "X_001", FLOOR_LAVA },
  46.     { "X_009", FLOOR_SLUDGE },
  47.     { "F_033", FLOOR_ICE },
  48.     { "END", -1 }
  49. };
  50.  
  51. // PRIVATE DATA DEFINITIONS ------------------------------------------------
  52.  
  53. static struct
  54. {
  55.     line_t *line;
  56.     int lineTag;
  57. } TaggedLines[MAX_TAGGED_LINES];
  58. static int TaggedLineCount;
  59.  
  60. mobj_t LavaInflictor;
  61.  
  62. // CODE --------------------------------------------------------------------
  63.  
  64. //==========================================================================
  65. //
  66. // P_InitLava
  67. //
  68. //==========================================================================
  69.  
  70. void P_InitLava(void)
  71. {
  72.     memset(&LavaInflictor, 0, sizeof(mobj_t));
  73.     LavaInflictor.type = MT_CIRCLEFLAME;
  74.     LavaInflictor.flags2 = MF2_FIREDAMAGE|MF2_NODMGTHRUST;
  75. }
  76.  
  77. //==========================================================================
  78. //
  79. // P_InitTerrainTypes
  80. //
  81. //==========================================================================
  82.  
  83. void P_InitTerrainTypes(void)
  84. {
  85.     int i;
  86.     int lump;
  87.     int size;
  88.  
  89.     size = (numflats+1)*sizeof(int);
  90.     TerrainTypes = Z_Malloc(size, PU_STATIC, 0);
  91.     memset(TerrainTypes, 0, size);
  92.     for(i = 0; TerrainTypeDefs[i].type != -1; i++)
  93.     {
  94.         lump = W_CheckNumForName(TerrainTypeDefs[i].name);
  95.         if(lump != -1)
  96.         {
  97.             TerrainTypes[lump-firstflat] = TerrainTypeDefs[i].type;
  98.         }
  99.     }
  100. }
  101.  
  102. //==========================================================================
  103. //
  104. // getSide
  105. //
  106. // Will return a side_t* given the number of the current sector, the
  107. // line number, and the side (0/1) that you want.
  108. //
  109. //==========================================================================
  110.  
  111. /*
  112. side_t *getSide(int currentSector, int line, int side)
  113. {
  114.     return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ];
  115. }
  116. */
  117.  
  118. //==========================================================================
  119. //
  120. // getSector
  121. //
  122. // Will return a sector_t* given the number of the current sector, the
  123. // line number, and the side (0/1) that you want.
  124. //
  125. //==========================================================================
  126.  
  127. /*
  128. sector_t *getSector(int currentSector, int line, int side)
  129. {
  130.     return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector;
  131. }
  132. */
  133.  
  134. //==========================================================================
  135. //
  136. // twoSided
  137. //
  138. // Given the sector number and the line number, will tell you whether
  139. // the line is two-sided or not.
  140. //
  141. //==========================================================================
  142.  
  143. /*
  144. int     twoSided(int sector, int line)
  145. {
  146.     return (sectors[sector].lines[line])->flags & ML_TWOSIDED;
  147. }
  148. */
  149.  
  150. //==================================================================
  151. //
  152. //      Return sector_t * of sector next to current. NULL if not two-sided line
  153. //
  154. //==================================================================
  155. sector_t *getNextSector(line_t *line,sector_t *sec)
  156. {
  157.     if (!(line->flags & ML_TWOSIDED))
  158.         return NULL;
  159.  
  160.     if (line->frontsector == sec)
  161.         return line->backsector;
  162.  
  163.     return line->frontsector;
  164. }
  165.  
  166. //==================================================================
  167. //
  168. //      FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS
  169. //
  170. //==================================================================
  171. fixed_t P_FindLowestFloorSurrounding(sector_t *sec)
  172. {
  173.     int                     i;
  174.     line_t          *check;
  175.     sector_t        *other;
  176.     fixed_t         floor = sec->floorheight;
  177.  
  178.     for (i=0 ;i < sec->linecount ; i++)
  179.     {
  180.         check = sec->lines[i];
  181.         other = getNextSector(check,sec);
  182.         if (!other)
  183.             continue;
  184.         if (other->floorheight < floor)
  185.             floor = other->floorheight;
  186.     }
  187.     return floor;
  188. }
  189.  
  190. //==================================================================
  191. //
  192. //      FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS
  193. //
  194. //==================================================================
  195. fixed_t P_FindHighestFloorSurrounding(sector_t *sec)
  196. {
  197.     int                     i;
  198.     line_t          *check;
  199.     sector_t        *other;
  200.     fixed_t         floor = -500*FRACUNIT;
  201.  
  202.     for (i=0 ;i < sec->linecount ; i++)
  203.     {
  204.         check = sec->lines[i];
  205.         other = getNextSector(check,sec);
  206.         if (!other)
  207.             continue;
  208.         if (other->floorheight > floor)
  209.             floor = other->floorheight;
  210.     }
  211.     return floor;
  212. }
  213.  
  214. //==================================================================
  215. //
  216. //      FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS
  217. //
  218. //==================================================================
  219. fixed_t P_FindNextHighestFloor(sector_t *sec,int currentheight)
  220. {
  221.     int                     i;
  222.     int                     h;
  223.     int                     min;
  224.     line_t          *check;
  225.     sector_t        *other;
  226.     fixed_t         height = currentheight;
  227.     fixed_t         heightlist[20];         // 20 adjoining sectors max!
  228.  
  229.     for (i =0,h = 0 ;i < sec->linecount ; i++)
  230.     {
  231.         check = sec->lines[i];
  232.         other = getNextSector(check,sec);
  233.         if (!other)
  234.             continue;
  235.         if (other->floorheight > height)
  236.             heightlist[h++] = other->floorheight;
  237.     }
  238.  
  239.     //
  240.     // Find lowest height in list
  241.     //
  242.     min = heightlist[0];
  243.     for (i = 1;i < h;i++)
  244.         if (heightlist[i] < min)
  245.             min = heightlist[i];
  246.  
  247.     return min;
  248. }
  249.  
  250. //==================================================================
  251. //
  252. //      FIND LOWEST CEILING IN THE SURROUNDING SECTORS
  253. //
  254. //==================================================================
  255. fixed_t P_FindLowestCeilingSurrounding(sector_t *sec)
  256. {
  257.     int                     i;
  258.     line_t          *check;
  259.     sector_t        *other;
  260.     fixed_t         height = MAXINT;
  261.  
  262.     for (i=0 ;i < sec->linecount ; i++)
  263.     {
  264.         check = sec->lines[i];
  265.         other = getNextSector(check,sec);
  266.         if (!other)
  267.             continue;
  268.         if (other->ceilingheight < height)
  269.             height = other->ceilingheight;
  270.     }
  271.     return height;
  272. }
  273.  
  274. //==================================================================
  275. //
  276. //      FIND HIGHEST CEILING IN THE SURROUNDING SECTORS
  277. //
  278. //==================================================================
  279. fixed_t P_FindHighestCeilingSurrounding(sector_t *sec)
  280. {
  281.     int     i;
  282.     line_t  *check;
  283.     sector_t        *other;
  284.     fixed_t height = 0;
  285.  
  286.     for (i=0 ;i < sec->linecount ; i++)
  287.     {
  288.         check = sec->lines[i];
  289.         other = getNextSector(check,sec);
  290.         if (!other)
  291.             continue;
  292.         if (other->ceilingheight > height)
  293.             height = other->ceilingheight;
  294.     }
  295.     return height;
  296. }
  297.  
  298. //==================================================================
  299. //
  300. //      RETURN NEXT SECTOR # THAT LINE TAG REFERS TO
  301. //
  302. //==================================================================
  303.  
  304. /*
  305. int     P_FindSectorFromLineTag(line_t  *line,int start)
  306. {
  307.     int     i;
  308.  
  309.     for (i=start+1;i<numsectors;i++)
  310.         if (sectors[i].tag == line->arg1)
  311.             return i;
  312.     return -1;
  313. }
  314. */
  315.  
  316. //=========================================================================
  317. //
  318. // P_FindSectorFromTag
  319. //
  320. //=========================================================================
  321.  
  322. int P_FindSectorFromTag(int tag, int start)
  323. {
  324.     int i;
  325.     
  326.     for(i = start+1; i < numsectors; i++)
  327.     {
  328.         if(sectors[i].tag == tag)
  329.         {
  330.             return i;
  331.         }
  332.     }
  333.     return -1;
  334. }
  335.  
  336. //==================================================================
  337. //
  338. //      Find minimum light from an adjacent sector
  339. //
  340. //==================================================================
  341.  
  342. /*
  343. int     P_FindMinSurroundingLight(sector_t *sector,int max)
  344. {
  345.     int                     i;
  346.     int                     min;
  347.     line_t          *line;
  348.     sector_t        *check;
  349.  
  350.     min = max;
  351.     for (i=0 ; i < sector->linecount ; i++)
  352.     {
  353.         line = sector->lines[i];
  354.         check = getNextSector(line,sector);
  355.         if (!check)
  356.             continue;
  357.         if (check->lightlevel < min)
  358.             min = check->lightlevel;
  359.     }
  360.     return min;
  361. }
  362. */
  363.  
  364. //=========================================================================
  365. //
  366. // EV_SectorSoundChange
  367. //
  368. //=========================================================================
  369.  
  370. boolean EV_SectorSoundChange(byte *args)
  371. {
  372.     int secNum;
  373.     boolean rtn;
  374.  
  375.     if(!args[0])
  376.     {
  377.         return false;
  378.     }
  379.     secNum = -1;
  380.     rtn = false;
  381.     while((secNum = P_FindSectorFromTag(args[0], secNum)) >= 0)
  382.     {
  383.         sectors[secNum].seqType = args[1];
  384.         rtn = true;
  385.     }
  386.     return rtn;
  387. }
  388.  
  389. //============================================================================
  390. //
  391. // CheckedLockedDoor
  392. //
  393. //============================================================================
  394.  
  395. static boolean CheckedLockedDoor(mobj_t *mo, byte lock)
  396. {
  397.     extern char *TextKeyMessages[11];
  398.     char LockedBuffer[80];
  399.  
  400.     if(!mo->player)
  401.     {
  402.         return false;
  403.     }
  404.     if(!lock)
  405.     {    
  406.         return true;
  407.     }
  408.     if(!(mo->player->keys&(1<<(lock-1))))
  409.     {
  410.         sprintf(LockedBuffer, "YOU NEED THE %s\n", 
  411.             TextKeyMessages[lock-1]);
  412.         P_SetMessage(mo->player, LockedBuffer, true);
  413.         S_StartSound(mo, SFX_DOOR_LOCKED);
  414.         return false;
  415.     }
  416.     return true;
  417. }
  418.  
  419.  
  420. //==========================================================================
  421. //
  422. // EV_LineSearchForPuzzleItem
  423. //
  424. //==========================================================================
  425.  
  426. boolean EV_LineSearchForPuzzleItem(line_t *line, byte *args, mobj_t *mo)
  427. {
  428.     player_t *player;
  429.     int i;
  430.     artitype_t type,arti;
  431.  
  432.     if (!mo) return false;
  433.     player = mo->player;
  434.     if (!player) return false;
  435.  
  436.     // Search player's inventory for puzzle items
  437.     for (i=0; i<player->artifactCount; i++)
  438.     {
  439.         arti = player->inventory[i].type;
  440.         type = arti - arti_firstpuzzitem;
  441.         if (type < 0) continue;
  442.         if (type == line->arg1)
  443.         {
  444.             // A puzzle item was found for the line
  445.             if (P_UseArtifact(player, arti))
  446.             {
  447.                 // A puzzle item was found for the line
  448.                 P_PlayerRemoveArtifact(player, i);
  449.                 if(player == &players[consoleplayer])
  450.                 {
  451.                     if(arti < arti_firstpuzzitem)
  452.                     {
  453.                         S_StartSound(NULL, SFX_ARTIFACT_USE);
  454.                     }
  455.                     else
  456.                     {
  457.                         S_StartSound(NULL, SFX_PUZZLE_SUCCESS);
  458.                     }
  459.                     ArtifactFlash = 4;
  460.                 }
  461.                 return true;
  462.             }
  463.         }
  464.     }
  465.     return false;
  466. }
  467.  
  468.  
  469.  
  470. /*
  471. ==============================================================================
  472.  
  473.                             EVENTS
  474.  
  475. Events are operations triggered by using, crossing, or shooting special lines, or by timed thinkers
  476.  
  477. ==============================================================================
  478. */
  479. //============================================================================
  480. //
  481. // P_ExecuteLineSpecial
  482. //
  483. //============================================================================
  484.  
  485. boolean P_ExecuteLineSpecial(int special, byte *args, line_t *line, int side,
  486.     mobj_t *mo)
  487. {
  488.     boolean buttonSuccess;
  489.  
  490.     buttonSuccess = false;
  491.     switch(special)
  492.     {
  493.         case 1: // Poly Start Line
  494.             break;
  495.         case 2: // Poly Rotate Left
  496.             buttonSuccess = EV_RotatePoly(line, args, 1, false);
  497.             break;
  498.         case 3: // Poly Rotate Right
  499.             buttonSuccess = EV_RotatePoly(line, args, -1, false);
  500.             break;
  501.         case 4: // Poly Move
  502.             buttonSuccess = EV_MovePoly(line, args, false, false);
  503.             break;
  504.         case 5: // Poly Explicit Line:  Only used in initialization
  505.             break;
  506.         case 6: // Poly Move Times 8
  507.             buttonSuccess = EV_MovePoly(line, args, true, false);
  508.             break;
  509.         case 7: // Poly Door Swing
  510.             buttonSuccess = EV_OpenPolyDoor(line, args, PODOOR_SWING);
  511.             break;
  512.         case 8: // Poly Door Slide
  513.             buttonSuccess = EV_OpenPolyDoor(line, args, PODOOR_SLIDE);
  514.             break;
  515.         case 10: // Door Close
  516.             buttonSuccess = EV_DoDoor(line, args, DREV_CLOSE);
  517.             break;
  518.         case 11: // Door Open
  519.             if(!args[0])
  520.             {
  521.                 buttonSuccess = EV_VerticalDoor(line, mo);
  522.             }
  523.             else
  524.             {
  525.                 buttonSuccess = EV_DoDoor(line, args, DREV_OPEN);
  526.             }
  527.             break;
  528.         case 12: // Door Raise
  529.             if(!args[0])
  530.             {
  531.                 buttonSuccess = EV_VerticalDoor(line, mo);
  532.             }
  533.             else
  534.             {
  535.                 buttonSuccess = EV_DoDoor(line, args, DREV_NORMAL);
  536.             }
  537.             break;
  538.         case 13: // Door Locked_Raise
  539.             if(CheckedLockedDoor(mo, args[3]))
  540.             {
  541.                 if(!args[0])
  542.                 {
  543.                     buttonSuccess = EV_VerticalDoor(line, mo);
  544.                 }
  545.                 else
  546.                 {
  547.                     buttonSuccess = EV_DoDoor(line, args, DREV_NORMAL);
  548.                 }
  549.             }
  550.             break;
  551.         case 20: // Floor Lower by Value
  552.             buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOORBYVALUE);
  553.             break;
  554.         case 21: // Floor Lower to Lowest
  555.             buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOORTOLOWEST);
  556.             break;
  557.         case 22: // Floor Lower to Nearest
  558.             buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOOR);
  559.             break;
  560.         case 23: // Floor Raise by Value
  561.             buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORBYVALUE);
  562.             break;
  563.         case 24: // Floor Raise to Highest
  564.             buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOOR);
  565.             break;
  566.         case 25: // Floor Raise to Nearest
  567.             buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORTONEAREST);
  568.             break;
  569.         case 26: // Stairs Build Down Normal
  570.             buttonSuccess = EV_BuildStairs(line, args, -1, STAIRS_NORMAL);
  571.             break;
  572.         case 27: // Build Stairs Up Normal
  573.             buttonSuccess = EV_BuildStairs(line, args, 1, STAIRS_NORMAL);
  574.             break;
  575.         case 28: // Floor Raise and Crush
  576.             buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORCRUSH);
  577.             break;
  578.         case 29: // Build Pillar (no crushing)
  579.             buttonSuccess = EV_BuildPillar(line, args, false);
  580.             break;
  581.         case 30: // Open Pillar
  582.             buttonSuccess = EV_OpenPillar(line, args);
  583.             break;
  584.         case 31: // Stairs Build Down Sync
  585.             buttonSuccess = EV_BuildStairs(line, args, -1, STAIRS_SYNC);
  586.             break;
  587.         case 32: // Build Stairs Up Sync
  588.             buttonSuccess = EV_BuildStairs(line, args, 1, STAIRS_SYNC);
  589.             break;
  590.         case 35: // Raise Floor by Value Times 8
  591.             buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEBYVALUETIMES8);
  592.             break;
  593.         case 36: // Lower Floor by Value Times 8
  594.             buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERBYVALUETIMES8);
  595.             break;
  596.         case 40: // Ceiling Lower by Value
  597.             buttonSuccess = EV_DoCeiling(line, args, CLEV_LOWERBYVALUE);
  598.             break;
  599.         case 41: // Ceiling Raise by Value
  600.             buttonSuccess = EV_DoCeiling(line, args, CLEV_RAISEBYVALUE);
  601.             break;
  602.         case 42: // Ceiling Crush and Raise
  603.             buttonSuccess = EV_DoCeiling(line, args, CLEV_CRUSHANDRAISE);
  604.             break;
  605.         case 43: // Ceiling Lower and Crush
  606.             buttonSuccess = EV_DoCeiling(line, args, CLEV_LOWERANDCRUSH);
  607.             break;
  608.         case 44: // Ceiling Crush Stop
  609.             buttonSuccess = EV_CeilingCrushStop(line, args);
  610.             break;
  611.         case 45: // Ceiling Crush Raise and Stay
  612.             buttonSuccess = EV_DoCeiling(line, args, CLEV_CRUSHRAISEANDSTAY);
  613.             break;
  614.         case 46: // Floor Crush Stop
  615.             buttonSuccess = EV_FloorCrushStop(line, args);
  616.             break;
  617.         case 60: // Plat Perpetual Raise
  618.             buttonSuccess = EV_DoPlat(line, args, PLAT_PERPETUALRAISE, 0);
  619.             break;
  620.         case 61: // Plat Stop
  621.             EV_StopPlat(line, args);
  622.             break;
  623.         case 62: // Plat Down-Wait-Up-Stay
  624.             buttonSuccess = EV_DoPlat(line, args, PLAT_DOWNWAITUPSTAY, 0);
  625.             break;
  626.         case 63: // Plat Down-by-Value*8-Wait-Up-Stay
  627.             buttonSuccess = EV_DoPlat(line, args, PLAT_DOWNBYVALUEWAITUPSTAY,
  628.                 0);
  629.             break;
  630.         case 64: // Plat Up-Wait-Down-Stay
  631.             buttonSuccess = EV_DoPlat(line, args, PLAT_UPWAITDOWNSTAY, 0);
  632.             break;
  633.         case 65: // Plat Up-by-Value*8-Wait-Down-Stay
  634.             buttonSuccess = EV_DoPlat(line, args, PLAT_UPBYVALUEWAITDOWNSTAY,
  635.                 0);
  636.             break;
  637.         case 66: // Floor Lower Instant * 8
  638.             buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERTIMES8INSTANT);
  639.             break;
  640.         case 67: // Floor Raise Instant * 8
  641.             buttonSuccess = EV_DoFloor(line, args, FLEV_RAISETIMES8INSTANT);
  642.             break;
  643.         case 68: // Floor Move to Value * 8
  644.             buttonSuccess = EV_DoFloor(line, args, FLEV_MOVETOVALUETIMES8);
  645.             break;
  646.         case 69: // Ceiling Move to Value * 8
  647.             buttonSuccess = EV_DoCeiling(line, args, CLEV_MOVETOVALUETIMES8);
  648.             break;
  649.         case 70: // Teleport
  650.             if(side == 0)
  651.             { // Only teleport when crossing the front side of a line
  652.                 buttonSuccess = EV_Teleport(args[0], mo, true);
  653.             }
  654.             break;
  655.         case 71: // Teleport, no fog
  656.             if(side == 0)
  657.             { // Only teleport when crossing the front side of a line
  658.                 buttonSuccess = EV_Teleport(args[0], mo, false);
  659.             }
  660.             break;
  661.         case 72: // Thrust Mobj
  662.             if(!side) // Only thrust on side 0
  663.             {
  664.                 P_ThrustMobj(mo, args[0]*(ANGLE_90/64), args[1]<<FRACBITS);
  665.                 buttonSuccess = 1;
  666.             }
  667.             break;
  668.         case 73: // Damage Mobj
  669.             if(args[0])
  670.             {
  671.                 P_DamageMobj(mo, NULL, NULL, args[0]);
  672.             }
  673.             else
  674.             { // If arg1 is zero, then guarantee a kill
  675.                 P_DamageMobj(mo, NULL, NULL, 10000);
  676.             }
  677.             buttonSuccess = 1;
  678.             break;
  679.         case 74: // Teleport_NewMap
  680.             if(side == 0)
  681.             { // Only teleport when crossing the front side of a line
  682.                 if(!(mo && mo->player && mo->player->playerstate
  683.                     == PST_DEAD)) // Players must be alive to teleport
  684.                 {
  685.                     G_Completed(args[0], args[1]);
  686.                     buttonSuccess = true;
  687.                 }
  688.             }
  689.             break;
  690.         case 75: // Teleport_EndGame
  691.             if(side == 0)
  692.             { // Only teleport when crossing the front side of a line
  693.                 if(!(mo && mo->player && mo->player->playerstate
  694.                     == PST_DEAD)) // Players must be alive to teleport
  695.                 {
  696.                     buttonSuccess = true;
  697.                     if(deathmatch)
  698.                     { // Winning in deathmatch just goes back to map 1
  699.                         G_Completed(1, 0);
  700.                     }
  701.                     else
  702.                     { // Passing -1, -1 to G_Completed() starts the Finale
  703.                         G_Completed(-1, -1);
  704.                     }
  705.                 }
  706.             }
  707.             break;
  708.         case 80: // ACS_Execute
  709.             buttonSuccess =
  710.                 P_StartACS(args[0], args[1], &args[2], mo, line, side);
  711.             break;
  712.         case 81: // ACS_Suspend
  713.             buttonSuccess = P_SuspendACS(args[0], args[1]);
  714.             break;
  715.         case 82: // ACS_Terminate
  716.             buttonSuccess = P_TerminateACS(args[0], args[1]);
  717.             break;
  718.         case 83: // ACS_LockedExecute
  719.             buttonSuccess = P_StartLockedACS(line, args, mo, side);
  720.             break;
  721.         case 90: // Poly Rotate Left Override
  722.             buttonSuccess = EV_RotatePoly(line, args, 1, true);
  723.             break;
  724.         case 91: // Poly Rotate Right Override
  725.             buttonSuccess = EV_RotatePoly(line, args, -1, true);
  726.             break;
  727.         case 92: // Poly Move Override
  728.             buttonSuccess = EV_MovePoly(line, args, false, true);
  729.             break;
  730.         case 93: // Poly Move Times 8 Override
  731.             buttonSuccess = EV_MovePoly(line, args, true, true);
  732.             break;
  733.         case 94: // Build Pillar Crush 
  734.             buttonSuccess = EV_BuildPillar(line, args, true);
  735.             break;
  736.         case 95: // Lower Floor and Ceiling
  737.             buttonSuccess = EV_DoFloorAndCeiling(line, args, false);
  738.             break;
  739.         case 96: // Raise Floor and Ceiling
  740.             buttonSuccess = EV_DoFloorAndCeiling(line, args, true);
  741.             break;
  742.         case 109: // Force Lightning
  743.             buttonSuccess = true;
  744.             P_ForceLightning();
  745.             break;
  746.         case 110: // Light Raise by Value
  747.             buttonSuccess = EV_SpawnLight(line, args, LITE_RAISEBYVALUE);
  748.             break; 
  749.         case 111: // Light Lower by Value
  750.             buttonSuccess = EV_SpawnLight(line, args, LITE_LOWERBYVALUE);
  751.             break; 
  752.         case 112: // Light Change to Value
  753.             buttonSuccess = EV_SpawnLight(line, args, LITE_CHANGETOVALUE);
  754.             break; 
  755.         case 113: // Light Fade
  756.             buttonSuccess = EV_SpawnLight(line, args, LITE_FADE);
  757.             break; 
  758.         case 114: // Light Glow
  759.             buttonSuccess = EV_SpawnLight(line, args, LITE_GLOW);
  760.             break; 
  761.         case 115: // Light Flicker
  762.             buttonSuccess = EV_SpawnLight(line, args, LITE_FLICKER);
  763.             break; 
  764.         case 116: // Light Strobe
  765.             buttonSuccess = EV_SpawnLight(line, args, LITE_STROBE);
  766.             break; 
  767.         case 120: // Quake Tremor
  768.             buttonSuccess = A_LocalQuake(args, mo);
  769.             break;
  770.         case 129: // UsePuzzleItem
  771.             buttonSuccess = EV_LineSearchForPuzzleItem(line, args, mo);
  772.             break;
  773.         case 130: // Thing_Activate
  774.             buttonSuccess = EV_ThingActivate(args[0]);
  775.             break;
  776.         case 131: // Thing_Deactivate
  777.             buttonSuccess = EV_ThingDeactivate(args[0]);
  778.             break;
  779.         case 132: // Thing_Remove
  780.             buttonSuccess = EV_ThingRemove(args[0]);
  781.             break;
  782.         case 133: // Thing_Destroy
  783.             buttonSuccess = EV_ThingDestroy(args[0]);
  784.             break;
  785.         case 134: // Thing_Projectile
  786.             buttonSuccess = EV_ThingProjectile(args, 0);
  787.             break;
  788.         case 135: // Thing_Spawn
  789.             buttonSuccess = EV_ThingSpawn(args, 1);
  790.             break;
  791.         case 136: // Thing_ProjectileGravity
  792.             buttonSuccess = EV_ThingProjectile(args, 1);
  793.             break;
  794.         case 137: // Thing_SpawnNoFog
  795.             buttonSuccess = EV_ThingSpawn(args, 0);
  796.             break;
  797.         case 138: // Floor_Waggle
  798.             buttonSuccess = EV_StartFloorWaggle(args[0], args[1],
  799.                 args[2], args[3], args[4]);
  800.             break;
  801.         case 140: // Sector_SoundChange
  802.             buttonSuccess = EV_SectorSoundChange(args);
  803.             break;
  804.  
  805.         // Line specials only processed during level initialization
  806.         // 100: Scroll_Texture_Left
  807.         // 101: Scroll_Texture_Right
  808.         // 102: Scroll_Texture_Up
  809.         // 103: Scroll_Texture_Down
  810.         // 121: Line_SetIdentification
  811.  
  812.         // Inert Line specials
  813.         default:
  814.             break;
  815.     }
  816.     return buttonSuccess;
  817. }
  818.  
  819. //============================================================================
  820. //
  821. // P_ActivateLine
  822. //
  823. //============================================================================
  824.  
  825. boolean P_ActivateLine(line_t *line, mobj_t *mo, int side, int activationType)
  826. {
  827.     int lineActivation;
  828.     boolean repeat;
  829.     boolean buttonSuccess;
  830.  
  831.     lineActivation = GET_SPAC(line->flags);
  832.     if(lineActivation != activationType)
  833.     {
  834.         return false;
  835.     }
  836.     if(!mo->player && !(mo->flags&MF_MISSILE))
  837.     {
  838.         if(lineActivation != SPAC_MCROSS)
  839.         { // currently, monsters can only activate the MCROSS activation type
  840.              return false;
  841.         }
  842.         if(line->flags & ML_SECRET)
  843.             return false;           // never open secret doors
  844.     }
  845.     repeat = line->flags&ML_REPEAT_SPECIAL;
  846.     buttonSuccess = false;
  847.  
  848.     buttonSuccess = P_ExecuteLineSpecial(line->special, &line->arg1, line,
  849.         side, mo);
  850.     if(!repeat && buttonSuccess)
  851.     { // clear the special on non-retriggerable lines
  852.         line->special = 0;
  853.     }
  854.     if((lineActivation == SPAC_USE || lineActivation == SPAC_IMPACT) 
  855.         && buttonSuccess)
  856.     {
  857.         P_ChangeSwitchTexture(line, repeat);
  858.     }
  859.     return true;
  860. }
  861.  
  862. //----------------------------------------------------------------------------
  863. //
  864. // PROC P_PlayerInSpecialSector
  865. //
  866. // Called every tic frame that the player origin is in a special sector.
  867. //
  868. //----------------------------------------------------------------------------
  869.  
  870. void P_PlayerInSpecialSector(player_t *player)
  871. {
  872.     sector_t *sector;
  873.     static int pushTab[3] =
  874.     {
  875.         2048*5,
  876.         2048*10,
  877.         2048*25
  878.     };
  879.  
  880.     sector = player->mo->subsector->sector;
  881.     if(player->mo->z != sector->floorheight)
  882.     { // Player is not touching the floor
  883.         return;
  884.     }
  885.     switch(sector->special)
  886.     {
  887.         case 9: // SecretArea
  888.             player->secretcount++;
  889.             sector->special = 0;
  890.             break;
  891.  
  892.         case 201: case 202: case 203: // Scroll_North_xxx
  893.             P_Thrust(player, ANG90, pushTab[sector->special-201]);
  894.             break;
  895.         case 204: case 205: case 206: // Scroll_East_xxx
  896.             P_Thrust(player, 0, pushTab[sector->special-204]);
  897.             break;
  898.         case 207: case 208: case 209: // Scroll_South_xxx
  899.             P_Thrust(player, ANG270, pushTab[sector->special-207]);
  900.             break;
  901.         case 210: case 211: case 212: // Scroll_West_xxx
  902.             P_Thrust(player, ANG180, pushTab[sector->special-210]);
  903.             break;
  904.         case 213: case 214: case 215: // Scroll_NorthWest_xxx
  905.             P_Thrust(player, ANG90+ANG45, pushTab[sector->special-213]);
  906.             break;
  907.         case 216: case 217: case 218: // Scroll_NorthEast_xxx
  908.             P_Thrust(player, ANG45, pushTab[sector->special-216]);
  909.             break;
  910.         case 219: case 220: case 221: // Scroll_SouthEast_xxx
  911.             P_Thrust(player, ANG270+ANG45, pushTab[sector->special-219]);
  912.             break;
  913.         case 222: case 223: case 224: // Scroll_SouthWest_xxx
  914.             P_Thrust(player, ANG180+ANG45, pushTab[sector->special-222]);
  915.             break;
  916.  
  917.         case 40: case 41: case 42: case 43: case 44: case 45:
  918.         case 46: case 47: case 48: case 49: case 50: case 51:
  919.             // Wind specials are handled in (P_mobj):P_XYMovement
  920.             break;
  921.  
  922.         case 26: // Stairs_Special1
  923.         case 27: // Stairs_Special2
  924.             // Used in (P_floor):ProcessStairSector
  925.             break;
  926.  
  927.         case 198: // Lightning Special
  928.         case 199: // Lightning Flash special
  929.         case 200: // Sky2
  930.             // Used in (R_plane):R_Drawplanes
  931.             break;
  932.         default:
  933.             I_Error("P_PlayerInSpecialSector: "
  934.                 "unknown special %i", sector->special);
  935.     }
  936. }
  937.  
  938. //============================================================================
  939. //
  940. // P_PlayerOnSpecialFlat
  941. //
  942. //============================================================================
  943.  
  944. void P_PlayerOnSpecialFlat(player_t *player, int floorType)
  945. {
  946.     if(player->mo->z != player->mo->floorz)
  947.     { // Player is not touching the floor
  948.         return;
  949.     }
  950.     switch(floorType)
  951.     {
  952.         case FLOOR_LAVA:
  953.             if(!(leveltime&31))
  954.             {
  955.                 P_DamageMobj(player->mo, &LavaInflictor, NULL, 10);
  956.                 S_StartSound(player->mo, SFX_LAVA_SIZZLE);
  957.             }
  958.             break;
  959.         default:
  960.             break;
  961.     }
  962. }
  963.  
  964. //----------------------------------------------------------------------------
  965. //
  966. // PROC P_UpdateSpecials
  967. //
  968. //----------------------------------------------------------------------------
  969.  
  970. void P_UpdateSpecials(void)
  971. {
  972.     int i;
  973.  
  974.     // Handle buttons
  975.     for(i = 0; i < MAXBUTTONS; i++)
  976.     {
  977.         if(buttonlist[i].btimer)
  978.         {
  979.             buttonlist[i].btimer--;
  980.             if(!buttonlist[i].btimer)
  981.             {
  982.                 switch(buttonlist[i].where)
  983.                 {
  984.                     case SWTCH_TOP:
  985.                         sides[buttonlist[i].line->sidenum[0]].toptexture =
  986.                             buttonlist[i].btexture;
  987.                         break;
  988.                     case SWTCH_MIDDLE:
  989.                         sides[buttonlist[i].line->sidenum[0]].midtexture =
  990.                             buttonlist[i].btexture;
  991.                         break;
  992.                     case SWTCH_BOTTOM:
  993.                         sides[buttonlist[i].line->sidenum[0]].bottomtexture =
  994.                             buttonlist[i].btexture;
  995.                         break;
  996.                 }
  997.                 //S_StartSound((mobj_t *)&buttonlist[i].soundorg, sfx_switch);
  998.                 memset(&buttonlist[i], 0, sizeof(button_t));
  999.             }
  1000.         }
  1001.     }
  1002. }
  1003.  
  1004. /*
  1005. ==============================================================================
  1006.  
  1007.                             SPECIAL SPAWNING
  1008.  
  1009. ==============================================================================
  1010. */
  1011. /*
  1012. ================================================================================
  1013. = P_SpawnSpecials
  1014. =
  1015. = After the map has been loaded, scan for specials that
  1016. = spawn thinkers
  1017. =
  1018. ===============================================================================
  1019. */
  1020.  
  1021. short   numlinespecials;
  1022. line_t  *linespeciallist[MAXLINEANIMS];
  1023.  
  1024. void P_SpawnSpecials (void)
  1025. {
  1026.     sector_t        *sector;
  1027.     int             i;
  1028.  
  1029.     //
  1030.     //      Init special SECTORs
  1031.     //
  1032.     sector = sectors;
  1033.     for (i=0 ; i<numsectors ; i++, sector++)
  1034.     {
  1035.         if (!sector->special)
  1036.             continue;
  1037.         switch (sector->special)
  1038.         {
  1039.             case 1: // Phased light
  1040.                 // Hardcoded base, use sector->lightlevel as the index
  1041.                 P_SpawnPhasedLight(sector, 80, -1);
  1042.                 break;
  1043.             case 2: // Phased light sequence start
  1044.                 P_SpawnLightSequence(sector, 1);
  1045.                 break;
  1046.             // Specials 3 & 4 are used by the phased light sequences
  1047.  
  1048.             /*
  1049.             case 1:         // FLICKERING LIGHTS
  1050.                 P_SpawnLightFlash (sector);
  1051.                 break;
  1052.             case 2:         // STROBE FAST
  1053.                 P_SpawnStrobeFlash(sector,FASTDARK,0);
  1054.                 break;
  1055.             case 3:         // STROBE SLOW
  1056.                 P_SpawnStrobeFlash(sector,SLOWDARK,0);
  1057.                 break;
  1058.             case 4:         // STROBE FAST/DEATH SLIME
  1059.                 P_SpawnStrobeFlash(sector,FASTDARK,0);
  1060.                 sector->special = 4;
  1061.                 break;
  1062.             case 8:         // GLOWING LIGHT
  1063.                 P_SpawnGlowingLight(sector);
  1064.                 break;
  1065.             case 9:         // SECRET SECTOR
  1066.                 totalsecret++;
  1067.                 break;
  1068.             case 10:        // DOOR CLOSE IN 30 SECONDS
  1069.                 P_SpawnDoorCloseIn30 (sector);
  1070.                 break;
  1071.             case 12:        // SYNC STROBE SLOW
  1072.                 P_SpawnStrobeFlash (sector, SLOWDARK, 1);
  1073.                 break;
  1074.             case 13:        // SYNC STROBE FAST
  1075.                 P_SpawnStrobeFlash (sector, FASTDARK, 1);
  1076.                 break;
  1077.             case 14:        // DOOR RAISE IN 5 MINUTES
  1078.                 P_SpawnDoorRaiseIn5Mins (sector, i);
  1079.                 break;
  1080.             */
  1081.         }
  1082.     }
  1083.  
  1084.  
  1085.     //
  1086.     //      Init line EFFECTs
  1087.     //
  1088.     numlinespecials = 0;
  1089.     TaggedLineCount = 0;
  1090.     for(i = 0; i < numlines; i++)
  1091.     {
  1092.         switch(lines[i].special)
  1093.         {
  1094.             case 100: // Scroll_Texture_Left
  1095.             case 101: // Scroll_Texture_Right
  1096.             case 102: // Scroll_Texture_Up
  1097.             case 103: // Scroll_Texture_Down
  1098.                 linespeciallist[numlinespecials] = &lines[i];
  1099.                 numlinespecials++;
  1100.                 break;
  1101.             case 121: // Line_SetIdentification
  1102.                 if(lines[i].arg1)
  1103.                 {
  1104.                     if(TaggedLineCount == MAX_TAGGED_LINES)
  1105.                     {
  1106.                         I_Error("P_SpawnSpecials: MAX_TAGGED_LINES "
  1107.                             "(%d) exceeded.", MAX_TAGGED_LINES);
  1108.                     }
  1109.                     TaggedLines[TaggedLineCount].line = &lines[i];
  1110.                     TaggedLines[TaggedLineCount++].lineTag
  1111.                         = lines[i].arg1;
  1112.                 }
  1113.                 lines[i].special = 0;
  1114.                 break;
  1115.         }
  1116.     }
  1117.  
  1118.     //
  1119.     //      Init other misc stuff
  1120.     //
  1121.     for (i = 0;i < MAXCEILINGS;i++)
  1122.         activeceilings[i] = NULL;
  1123.     for (i = 0;i < MAXPLATS;i++)
  1124.         activeplats[i] = NULL;
  1125.     for (i = 0;i < MAXBUTTONS;i++)
  1126.         memset(&buttonlist[i],0,sizeof(button_t));
  1127.  
  1128.     // Initialize flat and texture animations
  1129.     P_InitFTAnims();
  1130. }
  1131.  
  1132. //==========================================================================
  1133. //
  1134. // P_FindLine
  1135. //
  1136. //==========================================================================
  1137.  
  1138. line_t *P_FindLine(int lineTag, int *searchPosition)
  1139. {
  1140.     int i;
  1141.  
  1142.     for(i = *searchPosition+1; i < TaggedLineCount; i++)
  1143.     {
  1144.         if(TaggedLines[i].lineTag == lineTag)
  1145.         {
  1146.             *searchPosition = i;
  1147.             return TaggedLines[i].line;
  1148.         }
  1149.     }
  1150.     *searchPosition = -1;
  1151.     return NULL;
  1152. }
  1153.